package com.turtle3d.formallanguage.grammar;

import java.util.ArrayList;
import java.util.Hashtable;

import com.turtle3d.formallanguage.symbol.Method;
import com.turtle3d.formallanguage.symbol.Symbol;
import com.turtle3d.formallanguage.symbol.SymbolClass;
import com.turtle3d.formallanguage.symbol.SymbolFactory;




/**
 * 
 * @author marek
 *
 */
public abstract class Grammar {
		
	private ArrayList<Symbol> axiom = new ArrayList<Symbol>();
	
	private Hashtable<Symbol, ProductionFamily> productions = new Hashtable<Symbol, ProductionFamily>();
	
	private ArrayList<Symbol> outputSymbolSequence = new ArrayList<Symbol>();		
	
	private int iteration=0;
	
	public ArrayList<Symbol> generateSymbolSequence(int iterations){
		ArrayList<Symbol> symbols = new ArrayList<Symbol>();
		
		symbols.addAll(axiom);
		
		for(iteration=0;iteration<iterations;iteration++)
			symbols=nextIteration(symbols);			
		
		return symbols;
	}
		
	public static String printSymbolSequence(ArrayList<Symbol> symbolSequence, boolean showParameters){
		String ret="";
		for(Symbol symbol:symbolSequence){
			if(showParameters)
				ret+=symbol;
			else
				ret+=symbol.getSymbol();
		}
		
		return ret;	
		
	}
	
	public Production getProduction(Symbol leftSide){
		return productions.get(leftSide).getProduction();
	}
		
	
	public ArrayList<Symbol> nextIteration(ArrayList<Symbol> symbolSequence){
		
		ArrayList<Symbol> output = new ArrayList<Symbol>();
		
		for(Symbol symbol: symbolSequence)
		{
			if(productions.containsKey(symbol)){
				ArrayList<SymbolClass> rightSide = getProduction(symbol).getRightSide();
				
				//Compute production
				for(int j=0;j<rightSide.size();j++){
					Symbol s = new Symbol(rightSide.get(j));									
					s.setBirthIteration(iteration);
					boolean useThisSymbol = true;
					
						//Parametric calculations
						for(Method method: s.getSymbolClass().getMethods()){
							useThisSymbol=method.calculate(symbol, s); //NullPointer!
						}							
											
					if(useThisSymbol)
						output.add(s);					
					
				}
				
			}
			else
			{
				//just rewrite symbol
				output.add(symbol);
			}
			
			
		}
		
		return output;
		
	}
		
	public void addProduction(Production production){
		if(productions.get(production.getLeftSide())==null)
			productions.put(production.getLeftSide(), new ProductionFamily(production.getLeftSide()));
		
		productions.get(production.getLeftSide()).addProduction(production);				
	}

	public String getName()
	{
		return this.getClass().getSimpleName();
	}
	
	public Float getDefaultParameter(String name){
		return getDefaultParameters().get(name);
	}
	
	public Float setDefaultParameter(String name, Float value){
		return getDefaultParameters().put(name, value);
	}
	
	public Hashtable<String, Float> getDefaultParameters(){
		return SymbolFactory.getSymbolFactory().getDefaultParameters();
	}
		
	public final void init(){
		SymbolFactory.reset();
		define();
	}
	
	/**
	 * Grammar definition goes here.
	 *
	 */
	public abstract void define();

	public ArrayList<Symbol> getAxiom()
	{
		return axiom;
	}

	public void setAxiom(ArrayList<Symbol> axiom)
	{
		this.axiom = axiom;
	}
	
	public void setAxiom(Symbol symbol){
		axiom.add(symbol);
	}
					
}
